﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ERF;
using ERF.Physics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using FirstPerson.Objects.Pickups;
using FirstPerson.Objects.Weapons;
using ERF.Input;
using Microsoft.Xna.Framework.Audio;

namespace FirstPerson.Objects
{
    
    /// <summary>
    ///  Represents a local human player.
    /// </summary>
    public class HumanPlayer : NetworkPlayer
    {
        private GameTime currentGameTime;
        private Matrix parentMatrix;
        private const float JUMP_FORCE = 5000;
        private const float MOVEMENT_FORCE = 550;
        private IInputHandler input;
        private bool enabled = true;

        public bool Movable
        {
            get { return enabled; }
            set { enabled = value; }
        }

        public override Vector3 ForwardVector
        {
            get
            {
                return this.world.Backward;
            }
        }

        /// <summary>
        ///  Creates a new instance of HumanPlayer.
        /// </summary>
        /// <param name="game">The game this instance belongs to.</param>
        /// <param name="mass">The mass, in kg, of the player.</param>
        public HumanPlayer(ERFGame game, NetworkGamer gamer) : base(game, "Vincent", gamer) {
            this.Visible = false;
            base.CurrentWeapon.Hit += new EventHandler<WeaponHitEventArgs>(CurrentWeapon_Hit);

        }

        private void CurrentWeapon_Hit(object sender, WeaponHitEventArgs e) {
            WeaponBase weapon = sender as WeaponBase;
            if (e.Player is NetworkPlayer) {
                byte b1 = (byte)(sender as WeaponBase).Damage;
                byte b2 = (e.Player as NetworkPlayer).NetworkGamer.Id;
                short idDmg = (short)(((short)b2 << 8) | b1);
                (this.CurrentGame.NetworkHandler as NetworkHandler).Send(NetworkHandler.packetType.Hit, idDmg);
            }
        }

        public override void TakeDamage(int dmg, NetworkPlayer np) {
            base.Hp -= dmg;
            if (base.Hp <= 0) {
                (this.CurrentGame.NetworkHandler as NetworkHandler).Send(NetworkHandler.packetType.Killed, np.NetworkGamer.Id);
                this.Died(np);
            }
        }

        /// <summary>
        /// Handles the Bodys BodyChanged event and positions the camera accordingly.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected override void body_BodyChanged(object sender, EventArgs e) {
            base.body_BodyChanged(sender, e);

            
            CurrentGame.Camera.Position = base.EyePosition;

            base.Update(this.currentGameTime, ref this.parentMatrix);
        }

        /// <summary>
        /// Handles the Bodys BodyCollided event.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected override void body_BodyCollided(object sender, PhysicsEngine.BodyCollidedEventArgs e)
        {
            base.body_BodyCollided(sender, e);
        }

        public override void Update(GameTime gameTime, ref Matrix world)
        {
            this.currentGameTime = gameTime;
            this.parentMatrix = world;
             this.input = this.CurrentGame.Input;

            if(enabled)
                this.HandleInput(gameTime);
            
        }

        private void HandleInput(GameTime gameTime)
        {
            // Movement input.
            Vector3 translation = Vector3.Zero;
            Matrix cameraWorld = base.CurrentGame.Camera.World;

            Vector2 pos = input.GetDeviceLocation("MOVE");
            if (pos.Length() != 0)
            {
                translation += (pos.X * cameraWorld.Right) + (pos.Y * cameraWorld.Forward);
            }
            else
            {
                if (input.IsButtonDown("FORWARD_BUTTON", gameTime, false))
                    translation += cameraWorld.Forward;
                else if (input.IsButtonDown("BACKWARD_BUTTON", gameTime, false))
                    translation += cameraWorld.Backward;
                if (input.IsButtonDown("STRAFE_LEFT_BUTTON", gameTime, false))
                    translation += cameraWorld.Left;
                else if (input.IsButtonDown("STRAFE_RIGHT_BUTTON", gameTime, false))
                    translation += cameraWorld.Right;
            }

            if (translation != Vector3.Zero)
            {
                translation.Normalize();
                base.IsMoving = true;
            }
            else
            {
                base.IsMoving = false;
            }

            translation *= MOVEMENT_FORCE;
            this.body.internalForce = (translation);

            if (body.isOnGround && input.IsButtonDown("JUMP_BUTTON", gameTime, false))
                this.body.force.Y = JUMP_FORCE;
            
            // Aim input.
            Vector2 rotation = base.CurrentGame.Camera.Rotation;
            
            Vector2 analogMovement = input.GetDeviceLocation("AIM");
            rotation -= new Vector2(analogMovement.Y, analogMovement.X);

            rotation.X = MathHelper.Clamp(rotation.X, -MathHelper.PiOver2, MathHelper.PiOver2);
            base.CurrentGame.Camera.Rotation = rotation;
            base.rotation = new Vector3(0, rotation.Y + MathHelper.Pi, 0);

            this.currentWeapon.Rotation = new Vector3(-rotation.X, 0, 0);

            // Shoot input.
            if (input.IsButtonDown("SHOOT_BUTTON", gameTime, false))
                base.currentWeapon.BeginShooting();
            else
                base.currentWeapon.EndShooting();
        }
    }
}
